package com.ruicar.afs.cloud.account.common.component;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.account.common.dto.VoucherResult;
import com.ruicar.afs.cloud.account.common.entity.VoucherEntry;
import com.ruicar.afs.cloud.account.common.entity.VoucherInfo;
import com.ruicar.afs.cloud.account.common.entity.VoucherRuleInputMapping;
import com.ruicar.afs.cloud.account.common.entity.VoucherTemplateEvents;
import com.ruicar.afs.cloud.account.common.mapper.VoucherRuleInputMappingMapper;
import com.ruicar.afs.cloud.account.common.service.VoucherEntryService;
import com.ruicar.afs.cloud.account.common.service.VoucherInfoService;
import com.ruicar.afs.cloud.account.common.service.VoucherTemplateEventsService;
import com.ruicar.afs.cloud.common.config.VoucherConstant;
import com.ruicar.afs.cloud.common.core.service.ServiceInfo;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.common.data.lock.anno.Lock;
import com.ruicar.afs.cloud.common.datasync.componts.SyncHelper;
import com.ruicar.afs.cloud.common.modules.contract.enums.VoucherStatus;
import com.ruicar.afs.cloud.common.vo.VoucherEntryVo;
import com.ruicar.afs.cloud.common.vo.VoucherInfoVo;
import com.ruicar.afs.cloud.common.voucher.Voucher;
import com.ruicar.afs.cloud.common.voucher.VoucherAtomMapping;
import com.ruicar.afs.cloud.common.voucher.VoucherBaseInfo;
import com.ruicar.afs.cloud.common.voucher.VoucherGroup;
import com.ruicar.afs.cloud.common.voucher.handle.VoucherCaches;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
@AllArgsConstructor
public class VoucherPublishComponent implements ApplicationListener<ApplicationReadyEvent> {
    private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
    private final VoucherInfoService voucherInfoService;
    private final VoucherEntryService voucherEntryService;
    private final VoucherRuleInputMappingMapper voucherRuleInputMappingMapper;
    private final VoucherTemplateEventsService voucherTemplateEventsService;


    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        schedule();
    }

    @Lock(keyConstant=":lock-afs-voucher-publish",keys = "#serviceName")
    public void publishVouchers(String serviceName) {
        try {
            //加载已生效模板
            List<VoucherInfo> voucherInfos = voucherInfoService.
                    list(Wrappers.<VoucherInfo>lambdaQuery().eq(VoucherInfo::getStatus, VoucherStatus.ACTIVE));
            Map<String, VoucherGroup> voucherGroupMap = new HashMap<>();
            Map<String, VoucherGroup> groupMaps = new HashMap<>();
            Map<String,List<Long>>  buriedPointNos=new HashMap<>();
            for (VoucherInfo voucherInfo : voucherInfos) {
                List<VoucherEntry> entryList = voucherEntryService.list(Wrappers.<VoucherEntry>lambdaQuery().eq(VoucherEntry::getCorrelationId, voucherInfo.getId()));
                if (!groupMaps.containsKey(voucherInfo.getId().toString())) {
                    groupMaps.put(voucherInfo.getId().toString(), new VoucherGroup());
                    groupMaps.get(voucherInfo.getId().toString()).setInfos(new ArrayList<>());
                    VoucherBaseInfo info  =new VoucherBaseInfo();
                    VoucherInfoVo vo =new VoucherInfoVo();
                    BeanUtil.copyProperties(voucherInfo, vo);
                    info.setId(voucherInfo.getId());
                    info.setVoucherInfo(vo);
                    List<VoucherEntryVo> list=entryList.stream().map(entry -> {
                        VoucherEntryVo voucherEntryVo =new VoucherEntryVo();
                        BeanUtil.copyProperties(entry, voucherEntryVo);
                        return voucherEntryVo;
                    }).collect(Collectors.toList());
                    info.setEntryList(list);
                    groupMaps.get(voucherInfo.getId().toString()).getInfos().add(info);
                }
                entryList.forEach(voucherEntry -> {
                    if (!voucherGroupMap.containsKey(voucherEntry.getId().toString())) {
                        voucherGroupMap.put(voucherEntry.getId().toString(), new VoucherGroup());
                        voucherGroupMap.get(voucherEntry.getId().toString()).setVouchers(new ArrayList<>());
                        voucherGroupMap.get(voucherEntry.getId().toString()).getVouchers().add(loadVoucher(voucherEntry));
                    }
                });
            }
            Map<String, String> voucherCheck = new HashMap<>();
            voucherGroupMap.values().stream().forEach(group -> {
                group.getVouchers().stream().forEach(voucher -> {
                    voucherCheck.put(voucher.getRuleNo(), SecureUtil.md5(voucher.getRuleExpress()));
                });
            });
            //查询凭证事件
          voucherTemplateEventsService.list(Wrappers.<VoucherTemplateEvents>lambdaQuery().eq(VoucherTemplateEvents::getStatus, VoucherStatus.ACTIVE))
          .forEach(voucherTemplateEvents -> {
              for(VoucherInfo voucherInfo: voucherInfos){
                  if(voucherInfo.getMainBusinessCode().equals(voucherTemplateEvents.getMainBusinessCode())&&voucherInfo.getChildBusinessCode().equals(voucherTemplateEvents.getChildBusinessCode())){
                      if (!buriedPointNos.containsKey(voucherTemplateEvents.getBuriedPointNo())) {
                          List<Long> longs=new ArrayList<>();
                          longs.add(voucherInfo.getId());
                          buriedPointNos.put(voucherTemplateEvents.getBuriedPointNo(),longs);
                      }else{
                          List<Long> longs =buriedPointNos.get(voucherTemplateEvents.getBuriedPointNo());
                          longs.add(voucherInfo.getId());
                          buriedPointNos.put(voucherTemplateEvents.getBuriedPointNo(),longs);
                      }
                  }
              }
          });
            if (!voucherCheck.equals(VoucherCaches.getChecks())) {
                //增加凭证信息
                voucherGroupMap.putAll(groupMaps);
                voucherGroupMap.put("events", new VoucherGroup());
                voucherGroupMap.get("events").getEvents().putAll(buriedPointNos);
                JSONObject jsonObject = new JSONObject();
                jsonObject.putAll(voucherGroupMap);
                SyncHelper.publishParams(VoucherConstant.VOUCHER_SYNC_KEY, jsonObject);
            } else {
                log.info("缓存中凭证与发布凭证一致，跳过本次发布.........");
            }
        } catch (Throwable e) {
            log.error("凭证发布失败", e);
        }
    }

    private Voucher loadVoucher(VoucherEntry voucherEntry) {
        Voucher voucher = new Voucher();
        voucher.setRuleNo(voucherEntry.getId().toString());
        VoucherResult voucherResult = new VoucherResult();
        voucherResult.setRuleNo(voucherEntry.getId().toString());
        voucher.setRuleExpress(voucherEntry.getAmountExpression());
        List<VoucherAtomMapping> voucherAtomMappings = voucherRuleInputMappingMapper
                .selectList(Wrappers.<VoucherRuleInputMapping>lambdaQuery().eq(VoucherRuleInputMapping::getRuleId, voucherEntry.getId()))
                .stream()
                .map(voucherInputMapping -> {
                    VoucherAtomMapping voucherAtomMapping = new VoucherAtomMapping();
                    voucherAtomMapping.setValuePath(voucherInputMapping.getValueExpress());
                    voucherAtomMapping.setAtomKey(voucherInputMapping.getAtomKey());
                    voucherAtomMapping.setMappingName(voucherInputMapping.getMappingKey());
                    voucherAtomMapping.setAtomType(voucherInputMapping.getAtomType());
                    return voucherAtomMapping;
                }).collect(Collectors.toList());
        voucher.setVoucherAtomMappings(voucherAtomMappings);
        return voucher;
    }

    private void schedule() {
        //每10s 检测发布处理一次凭证取值
      EXECUTOR_SERVICE.scheduleWithFixedDelay(() -> {
            SpringContextHolder.getBean(VoucherPublishComponent.class).publishVouchers(ServiceInfo.getServiceName());
        }, 2, 10, TimeUnit.SECONDS);

    }
}
